package storage;

import java.io.IOException;
import java.util.Vector;

import javax.microedition.rms.*;

/**
 * A DAO pattern for Persistent type classes
 * 
 * @author Marcelo Gatto
 */

public class PersistentDAO {

	private RecordStore rs = null;

	private Class  persistentType;
	private String recordStoreName;

	
	public PersistentDAO(Persistent persistent) throws RecordStoreException {
		this.recordStoreName = persistent.getClass().getName();
		this.persistentType = persistent.getClass();
	}

	public RecordStore getRecordStore() {
		return rs;
	}

	/* -------------------- */
	/* Internal use methods */
	/* -------------------- */
	
	private void open() throws RecordStoreException {
		rs = RecordStore.openRecordStore(recordStoreName, true);
	}

	private void close() {
		if (rs != null) {
			try {
				rs.closeRecordStore();
			} catch (RecordStoreException e) {	}
			rs = null;
		}
	}

	/* --------------- */
	/* General Queries */
	/* --------------- */
	
	public int getNumRecord() throws RecordStoreException {
		try {
			open();
			return rs.getNumRecords();
		} catch (RecordStoreNotOpenException e) {
			return -1;
		}
		finally {
			close();
		}
	}
	
	public int getSize() throws RecordStoreException {
		try {
			open();
			return rs.getSize();
		} finally {
			close();
		}
	}
	
	/* -------------- */
	/* Update methods */
	/* -------------- */
	
	public void storeAll(Vector v) throws RecordStoreException {
		for(int i=0; i<v.size(); i++) {
			Object o = v.elementAt(i);
			if(!(o instanceof Persistent)) {
				throw new ClassCastException("Some object in vector is not a Persistent class");
			}
			store((Persistent)o);
		}
	}

	public Persistent store(Persistent persistent) throws RecordStoreException {
		try {
			open();
			if(persistent.getId()>0) {
				byte[] data = persistent.persist(persistent.getId());
				rs.setRecord(persistent.getId(), data, 0, data.length);
				return persistent;
			}
			
			int nextId = rs.getNextRecordID();
			byte[] data = persistent.persist(nextId);
			rs.addRecord(data, 0, data.length);
			return persistent;
		} catch (IOException e) {
			throw new RecordStoreException(e.getMessage());
		}
		finally {
			close();
		}
	}
	
	/* -------------- */
	/* Select methods */
	/* -------------- */
	
	public Persistent retrive(int id) throws RecordStoreException {
		try {
			open();
			byte[] data = rs.getRecord(id);
			Persistent per = (Persistent) persistentType.newInstance();
			per.resurrect(data);
			return per;
		} catch (InvalidRecordIDException e) {
			return null;
		} catch (IOException e) {
			throw new RecordStoreException(e.getMessage());
		} catch (InstantiationException e) {
			throw new RecordStoreException(e.getMessage());
		} catch (IllegalAccessException e) {
			throw new RecordStoreException(e.getMessage());
		}
		finally {
			close();
		}
	}
	
	public Vector retriveAll() throws RecordStoreException {
		return retriveAll(null, null);
	}
	
	public Vector retriveAll(PersistentFilter rFilter) throws RecordStoreException {
		rFilter.setPersistentType(persistentType);
		return retriveAll(rFilter, null);
	}
	
	public Vector retriveAll(PersistentComparator rComp) throws RecordStoreException {
		rComp.setPersistentType(persistentType);
		return retriveAll(null, rComp);
	}

	public Vector retriveAll(PersistentFilter pFilter, PersistentComparator pComp) throws RecordStoreException {
		open();
		RecordEnumeration recEnum = rs.enumerateRecords(pFilter, pComp, false);
		Vector result = new Vector();
		try {
			while (recEnum.hasNextElement()) {
				Persistent per = (Persistent) persistentType.newInstance();
				per.resurrect(recEnum.nextRecord());
				result.addElement(per);
			}
		} catch (InstantiationException e) {
			throw new RecordStoreException(e.getMessage());
		} catch (IllegalAccessException e) {
			throw new RecordStoreException(e.getMessage());
		} catch (IOException e) {
			throw new RecordStoreException(e.getMessage());
		} finally {
			recEnum = null;
			close();
		}
		
		return result;
	}
	
	/* -------------- */
	/* Delete methods */
	/* -------------- */
	
	public boolean delete(Persistent persistent) throws RecordStoreException {
		open();
		try {
			rs.deleteRecord(persistent.getId());
			return true;
		} catch (RecordStoreNotOpenException e) {
			throw new RecordStoreException(e.getMessage());
		} catch (InvalidRecordIDException e) {
			return false;
		} finally {
			close();
		}
	}
	
	public void deleteAll() throws RecordStoreException {
		Vector all = retriveAll();
		open();
		try {
			for(int i=0; i<all.size(); i++)
				rs.deleteRecord( ((Persistent)all.elementAt(i)).getId() );
		} catch (RecordStoreNotOpenException e) {
			throw new RecordStoreException(e.getMessage());
		} finally {
			all = null;
			close();
		}	
	}

}